#pragma once

#include<queue>
#include<pthread.h>
#include<unistd.h>

template<class T>
class ThreadPool
{
  private:
    std::queue<T> bq;

    pthread_mutex_t lock;

    pthread_cond_t cond;

    static ThreadPool<T>* instance;

//  public:
    ThreadPool()                //为实现单例，不把构造函数暴露出
    {
      pthread_mutex_init(&lock,nullptr);

      pthread_cond_init(&cond,nullptr);
    }

    ThreadPool(const ThreadPool<T>&t) =delete;
    ThreadPool<T>& operator=(const ThreadPool<T>& t) =delete;

    //不加static 函数会多一个参数
    static void* Routine(void*s)
    {
      ThreadPool* th=(ThreadPool*)s;
      //线程分离
      pthread_detach(pthread_self());
      while(1)
      {
        while(th->Isempty())
        {
          th->ThreadWait();
        }
        //提取任务
        T tmp;
        th->PopTask(&tmp);
        
        th->UnlockQueue();
        //做任务
        tmp();
        //sleep(1);
      }
    }
  public:
    static ThreadPool<T>* get_instance(int num)        //实现单例的函数
    {
      static pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;
      if(instance==nullptr)                    //注意这里锁的使用，保证临界区的安全
      {
          pthread_mutex_lock(&mtx);
          if(instance==nullptr)
          {
            instance=new ThreadPool<T>();
            instance->Init(5);
          }
          pthread_mutex_unlock(&mtx);
      }
      return instance;
    }
    void Init(int num)
    {
      pthread_t arr[num];
      int i=0;
      for(;i<num;i++)
      {
        pthread_create(arr+i,nullptr,Routine,(void*)this);
      }
    }
    //放任务
    void PushTask(const T& s)
    {
      LockQueue();
      bq.push(s);
      ThreadWakeup();
      UnlockQueue();
    }
    //提取任务
    void PopTask(T* s)
    {
      *s=bq.front();
      bq.pop();
    }
    bool Isempty()
    {
      return bq.size()==0?true:false;
    }
    ~ThreadPool()
    {
      pthread_mutex_destroy(&lock);

      pthread_cond_destroy(&cond);
    }
  private:
    void LockQueue()
    {
      pthread_mutex_lock(&lock);
    }
    void UnlockQueue()
    {
      pthread_mutex_unlock(&lock);
    }
    void ThreadWait()
    {
      pthread_cond_wait(&cond,&lock);
    }
    void ThreadWakeup()
    {
      pthread_cond_signal(&cond);
    }
};


template<class T>
ThreadPool<T>* ThreadPool<T>::instance=nullptr;
